#include "RowStructure.h"
#include "SQLError.h"
using namespace std;

RowStructure::RowStructure(void)
{
	tagA = 0;
	tagB = 0;
	fSize = 0;
	nCol = 0;
	varCount = 0;
	rowData = 0;
	fData = 0;
	nullBits = 0;
	varOffset = 0;
	varData = 0;
	recordLen = 0;
	tableInfo = NULL;
}

RowStructure::RowStructure(std::string name) : tableName(name)
{
	tableInfo = GetTableInfo(tableName);
	tagA = 0;
	tagB = 0;
	fSize = 0;
	nCol = 0;
	varCount = 0;
	rowData = 0;
	fData = 0;
	nullBits = 0;
	varOffset = 0;
	varData = 0;
	recordLen = 0;
}

void RowStructure::FillInRow(char * buf)
{
	rowData = buf;
	rowData[0] = tagA;
	//rowData[1] = tagB;
	*(short *)(rowData + 3) = fSize;
	for (int i = 0; i < fSize - 4; i ++)
	{
		rowData[5 + i] = fData[i];
	}
	*(short *)(rowData + fSize) = nCol;
	// Null bits
	for (int i = 0; i < (nCol + 7) / 8; i ++)
	{
		rowData[fSize + 2 + i] = nullBits[i];
	}

	*(short *)(rowData + fSize + 2 + (nCol + 7) / 8) = varCount;
	int lenBeforeVarData = fSize + 4 + (nCol +7) / 8 + 2 * varCount;
	for (int i = 0; i < varCount; i++)
	{
		*((short *)(rowData + fSize + 4 + (nCol + 7) / 8) + i) = varOffset[i + 1] + lenBeforeVarData;
	}

	for (int i = 0; i < varOffset[varCount]; i ++)
	{
		rowData[lenBeforeVarData + i] = varData[i];
	}

	*(short *)(rowData + 1) = varOffset[varCount] + lenBeforeVarData;
}

void RowStructure::ConstructData(const QueryInfo & q)
{
	TABLE_INFO * tableInfo = GetTableInfo(q.table_name[0]);
	int fixedOff,varOff,count;
	vector<string> varDataSet;
	count = 0;
	fixedOff = 0;
	varOff = 0;
	ReleaseResource();

	map<string, ColInfo> valueSet;
	valueSet.clear();
	for (size_t i = 0; i < q.col_name.size(); i ++)
	{
		valueSet[q.col_name[i].col_name] = q.col_name[i];
	}

	varCount = tableInfo->varColNum;
	fData = (char *)malloc(tableInfo->minLen);
	memset(fData, 0, tableInfo->minLen);
	varOffset = (short *)malloc(varCount * 2 + 2);
	nCol = (int)tableInfo->colInfo.size();
	nullBits = (char *)malloc((nCol + 7) / 8);
	memset(nullBits, 0, (nCol + 7) / 8);
	// fixed data size
	fSize = tableInfo->minLen + 5;
	for (int i = 0; i < nCol; i++)
	{
		ColInfo * pVal;
		bool notNull;
		if (valueSet.count(tableInfo->colInfo[i].name))
		{
			pVal = &valueSet[tableInfo->colInfo[i].name];
			notNull = true;
		}
		else
		{
			nullBits[i / 8] |= (1 << (i % 8));
			pVal = NULL;
			notNull = false;
		}

		switch (tableInfo->colInfo[i].xType)
		{
		case DATA_TYPE_INT:
			if (notNull)
			{
				if (pVal->value[0] == '\f')
					nullBits[i / 8] |= (1 << (i % 8));
				else
					*(int *)(fData + fixedOff) = atoi(pVal->value.c_str());
			}
			fixedOff += 4;
			break;
		case DATA_TYPE_CHAR:
			if (notNull)
			{
				if (pVal->value[0] == '\f')
					nullBits[i / 8] |= (1 << (i % 8));
				else
					memmove(fData + fixedOff, pVal->value.c_str(), pVal->value.size());
			}
			fixedOff += tableInfo->colInfo[i].length;
			break;
		case DATA_TYPE_VARCHAR:
			varOffset[count] = varOff;
			if (notNull)
			{
				if (pVal->value[0] == '\f')
					nullBits[i / 8] |= (1 << (i % 8));
				else
				{
					varOff += (int)pVal->value.size();
					varDataSet.push_back(pVal->value);
				}

			}
			count ++;
			break;
		default:
			break;
		}
	}
	varOffset[count] = varOff;
	varData = (char *)malloc(varOff);

	for (size_t i = 0; i < varDataSet.size(); i ++)
		memmove(varData + varOffset[i], varDataSet[i].c_str(), varDataSet[i].size());

	recordLen = fSize + 4 + (nCol +7) / 8 + 2 * varCount + varOff;
}

void RowStructure::ConstructData(std::map<std::string, std::string> & valueSet)
{
	int fixedOff,varOff,count;
	std::string * pVal;
	vector<string> varDataSet;
	count = 0;
	fixedOff = 0;
	varOff = 0;
	ReleaseResource();

	if (tableInfo == NULL)
		throw NullPointer("when construct row structure");
	varCount = tableInfo->varColNum;
	fData = (char *)malloc(tableInfo->minLen);
	memset(fData, 0, tableInfo->minLen);
	varOffset = (short *)malloc(varCount * 2 + 2);
	nCol = (int)tableInfo->colInfo.size();
	nullBits = (char *)malloc((nCol + 7) / 8);
	memset(nullBits, 0, (nCol + 7) / 8);
	// fixed data size
	fSize = tableInfo->minLen + 5;
	for (int i = 0; i < nCol; i++)
	{
		bool notNull;
		if (valueSet.count(tableInfo->colInfo[i].name))
		{
			pVal = &valueSet[tableInfo->colInfo[i].name];
			notNull = true;
		}
		else
		{
			nullBits[i / 8] |= (1 << (i % 8));
			pVal = NULL;
			notNull = false;
		}

		switch (tableInfo->colInfo[i].xType)
		{
		case DATA_TYPE_INT:
			if (notNull)
			{
				if ((*pVal)[0] == '\f')
					nullBits[i / 8] |= (1 << (i % 8));
				else
					*(int *)(fData + fixedOff) = atoi(pVal->c_str());
			}
			fixedOff += 4;
			break;
		case DATA_TYPE_CHAR:
			if (notNull)
			{
				if ((*pVal)[0] == '\f')
					nullBits[i / 8] |= (1 << (i % 8));
				else
					memmove(fData + fixedOff, pVal->c_str(), pVal->size());
			}
			fixedOff += tableInfo->colInfo[i].length;
			break;
		case DATA_TYPE_VARCHAR:
			varOffset[count] = varOff;
			if (notNull)
			{
				if ((*pVal)[0] == '\f')
					nullBits[i / 8] |= (1 << (i % 8));
				else
				{
					varOff += (int)pVal->size();
					varDataSet.push_back(*pVal);
				}

			}
			count ++;
			break;
		default:
			break;
		}
	}
	varOffset[count] = varOff;
	varData = (char *)malloc(varOff);

	for (size_t i = 0; i < varDataSet.size(); i ++)
		memmove(varData + varOffset[i], varDataSet[i].c_str(), varDataSet[i].size());

	recordLen = fSize + 4 + (nCol +7) / 8 + 2 * varCount + varOff;
}

void RowStructure::ParseColumns(char * row, std::string tablename)
{
	ReleaseResource();
	TABLE_INFO * tableInfo = GetTableInfo(tablename);
	rowData = row;
	tagA = rowData[0];
	tagB = *(short *)(rowData + 1);
	fSize = *(short *)(rowData + 3);
	fData = rowData + 5;
	nCol = *(short *)(rowData + fSize);
	varCount = *(short *)(rowData + fSize + 2 + (nCol + 7) / 8);
	int lenBeforeVarData = fSize + 4 + (nCol +7) / 8 + 2 * varCount;
	nullBits = rowData + fSize + 2;
	varOffset = (short *)(rowData + fSize + 4 + (nCol + 7) / 8);
	varData = rowData + lenBeforeVarData;

	bool notNull;
	int fixedOff = 0, count = 0, varStart = lenBeforeVarData;
	char num[30],buf[300];
	for (int i = 0; i < nCol; i++)
	{
		if (nullBits[i / 8] & (1 << (i % 8)))
			notNull = false;
		else
			notNull = true;
		switch (tableInfo->colInfo[i].xType)
		{
		case DATA_TYPE_INT:
			if (notNull)
			{
				int val = *(int *)(fData + fixedOff);
				_itoa_s(val, num, 30, 10);
				std::string sNum = num;
				columns[tableInfo->colInfo[i].name] = sNum;
			}
			else
				columns[tableInfo->colInfo[i].name] = '\f';
			fixedOff += 4;
			break;
		case DATA_TYPE_CHAR:
			if (notNull)
			{
				memmove(buf,fData + fixedOff,tableInfo->colInfo[i].length);
				buf[tableInfo->colInfo[i].length] = 0;
				columns[tableInfo->colInfo[i].name] = buf;
			}
			else
				columns[tableInfo->colInfo[i].name] = '\f';
			fixedOff += tableInfo->colInfo[i].length;
			break;
		case DATA_TYPE_VARCHAR:
			if (notNull)
			{
				memmove(buf,rowData + varStart, varOffset[count] - varStart);
				buf[varOffset[count] - varStart] = 0;
				columns[tableInfo->colInfo[i].name] = buf;
				varStart = varOffset[count];
			}
			else
				columns[tableInfo->colInfo[i].name] = '\f';
			count ++;
			break;
		default:
			break;
		}
	}
	fData = NULL;
	nullBits = NULL;
	varOffset = NULL;
	varData = NULL;
}

void RowStructure::ReleaseResource()
{
	if (fData != NULL)
		free(fData);
	if (nullBits != NULL)
		free(nullBits);
	if (varOffset != NULL)
		free(varOffset);
	if (varData != NULL)
		free(varData);
	fData = NULL;
	nullBits = NULL;
	varOffset = NULL;
	varData = NULL;
}

RowStructure::~RowStructure(void)
{
	ReleaseResource();
}
